﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Threading;

using agree.schema;

using alib;
using alib.Array;
using alib.Concurrency;
using alib.Enumerable;
using alib.Collections;
using alib.Collections.ReadOnly;
using alib.Debugging;

namespace agree
{
	public static class _tfs_analysis_ext
	{
		public static ulong FindAccessibleIndices(this ITfsSlot ts)
		{
			agree.Edge e = ts.Edge();
			return (e.FlagsId & agree.Edge.Flag.EtmNonBareType) != 0 ? new _accessible_indexes_helper(ts.Tfs, e).Result : 0;
		}

		/// <summary>
		/// Logical equality comparison of arbitrary substructure, regardless of the hosting ArrayTfs
		/// </summary>
		public static bool SubstructureEquals(this ITfsSlot _this, ITfsSlot other)
		{
			return Subsumption.Check(null, _this, other) == Subsumption.Equivalent;
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public unsafe struct _accessible_indexes_helper
	{
		public _accessible_indexes_helper(Tfs tfs, Edge start_edge)
		{
			FeatMgr ftm = tfs.ftm;
			this.tfs = tfs;
			this.ifeat_instloc = ftm.mrsm.ifeat_instloc;
			this.rgpfix = ftm.GenerationRestrictors.r_pack_args.R;
			this.Result = 0;
			if ((start_edge.FlagsId & Edge.Flag.EtmNonBareType) != 0)
				_walk_tfs(start_edge.FlagsId, start_edge.Mark);
		}

		public _accessible_indexes_helper(Tfs tfs)
			: this(tfs, tfs._top_edge)
		{
		}

		readonly Tfs tfs;
		readonly ushort** rgpfix;
		readonly int ifeat_instloc;
		public ulong Result;

		void _walk_tfs(Edge.Flag f, int m)
		{
			Edge.Flag nf;
			ushort* pfix;
			int nm, i_feat = *(pfix = *(ushort**)((long)rgpfix + ((int)f << 3)));
			do
				if ((nf = tfs.TryGetFlagsMark(i_feat, m, out nm)) != 0)
				{
					if (i_feat == ifeat_instloc && nf.IsSkolemValue())
						Result |= (ulong)1 << ((int)(nf & Edge.Flag.subid_mask) - 1);
					if ((nf & Edge.Flag.EtmNonBareType) != 0)
						_walk_tfs(nf, nm);
				}
			while ((i_feat = *++pfix) != 0xFFFF);
		}
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public unsafe struct EdgeCounter
	{
		readonly Tfs tfs;
		readonly ushort** rgpfix;

		public EdgeCounter(ITfsSlot ts)
		{
			this.tfs = ts.Tfs;
			this.rgpfix = tfs.ftm.r_none.R;
			this.CorefTallies = new byte[tfs.c_corefs];
			this.EffectiveCorefCount = 0;
			this.EdgeCount = 0;
			this.NodeCount = 1;		// including start node
			this.MaxMark = int.MinValue;

			_tally_section(ts.SlotIndex == 0 ? tfs._top_edge : tfs.entries[ts.SlotIndex - 1].e);
		}

		public readonly byte[] CorefTallies;
		public int EffectiveCorefCount;
		public int NodeCount;
		public int EdgeCount;
		public int MaxMark;

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		void _tally_section(Edge e)
		{
			ushort* pfix;
			int m, i_feat = *(pfix = *(ushort**)((long)rgpfix + ((int)e.FlagsId << 3)));
			if ((m = e.Mark) > MaxMark)
				MaxMark = m;
			do
			{
				Edge ne;
				if (tfs.GetEdgeIndex(i_feat, m, &ne) > 0)
				{
					EdgeCount++;
					if (ne.FlagsId < 0)
					{
						if (CorefTallies[~ne.Mark]++ > 0)
							continue;
						EffectiveCorefCount++;
					}
					NodeCount++;
					if ((ne.FlagsId & Edge.Flag.EtmNonBareType) != 0)
						_tally_section(ne);
				}
			}
			while ((i_feat = *++pfix) != 0xFFFF);
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class SubstructureEqualityComparer : IEqualityComparer<ITfsSlot>
	{
		public static readonly IEqualityComparer<ITfsSlot> Instance;
		static SubstructureEqualityComparer() { Instance = new SubstructureEqualityComparer(); }
		SubstructureEqualityComparer() { }
		public bool Equals(ITfsSlot x, ITfsSlot y)
		{
			return (Object)x == (Object)y || Subsumption.Check(null, x, y) == Subsumption.Equivalent;
		}
		public int GetHashCode(ITfsSlot obj)
		{
			return (Object)obj == default(Object) ? 0 : 1;
		}
	};
}